using System;
using System.Collections.Generic;

namespace NAsserter.Impl
{
    public class NullArgumentExpressionsImpl<T> : BaseArgumentExpression, IArgumentExpressions<T>
    {
        private static readonly IArgumentExpressions<T> _instance = new NullArgumentExpressionsImpl<T>();

        /// <summary>
        /// Retrieves a singleton instance.
        /// </summary>
        internal static IArgumentExpressions<T> Instance { get { return _instance; } }
        /// <summary>
        /// The description of this argument.  This is usually just the name unless overriden by a nested expression.
        /// </summary>
        public string Description
        {
            get { return default(string); }
        }

        /// <summary>
        /// The argument name.
        /// </summary>
        public string Name
        {
            get { return default(string); }
        }

        /// <summary>
        /// The value of the argument that assertions will be made against.
        /// </summary>
        public T Value
        {
            get { return default(T); }
        }

        /// <summary>
        /// Evaluate a Range expression.
        /// </summary>
        /// <returns>A nested ArgumentExpressionsImpl for method chaining.</returns>
        public IBetweenExpression<T> Between(T start)
        {
            return new NullBetweenExpression<T>(this, start);
        }

        /// <summary>
        /// Throws an exception if the argument value does not exist within the target args.
        /// </summary>
        /// <param name="args">The available values that the argument must exist within.</param>
        /// <exception cref="NotExistsArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        public IArgumentExpressions<T> Exists(params T[] args)
        {
            return this;
        }

        /// <summary>
        /// Throws an exception if the argument value does not exist within the target args.
        /// </summary>
        /// <param name="existsInEnumerable">The available values that the argument must exist within.</param>
        /// <exception cref="NotExistsArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        public IArgumentExpressions<T> Exists(IEnumerable<T> existsInEnumerable)
        {
            return this;
        }

        /// <summary>
        /// Allows for method chaining of a boolean condition.
        /// </summary>
        /// <param name="resultFromExpression">A boolean which is a result of an expression.</param>
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        public IArgumentExpressions<T> If(bool resultFromExpression)
        {
            return this;
        }

        /// <summary>
        /// Allows for method chaining of a boolean condition.
        /// </summary>
        /// <param name="condition">A predicate expressing a boolean condition.</param>
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        public IArgumentExpressions<T> If(Predicate<T> condition)
        {
            return this;
        }

        public IArgumentExpressions<T> Is(T value)
        {
            return this;
        }

        public IArgumentExpressions<T> IsNot(T value)
        {
            return this;
        }

        /// <summary>
        /// Throws an exception if the argument value is its default value based on its type.
        /// </summary>
        /// <exception cref="ArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        public IArgumentExpressions<T> IsNotDefault()
        {
            return this;
        }

        /// <summary>
        /// Throws an exception if the argument value is a null value.
        /// </summary>
        /// <exception cref="ArgumentNullException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        public IArgumentExpressions<T> IsNotNull()
        {
            return this;
        }

        /// <summary>
        /// Throws an exception if the argument value is Null or an empty string..
        /// </summary>
        /// <exception cref="ArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        public IArgumentExpressions<T> IsNotNullOrEmpty()
        {
            return this;
        }

        /// <summary>
        /// Throws an exception if condition does not evaluate to False.
        /// </summary>
        /// <param name="condition">Condition to be evaluated.</param>
        /// <exception cref="ArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        public IArgumentExpressions<T> IsFalse(Predicate<T> condition)
        {
            return this;
        }

        /// <summary>
        /// Throws an exception if condition does not evaluate to True.
        /// </summary>
        /// <param name="condition">Condition to be evaluated.</param>
        /// <exception cref="ArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        public IArgumentExpressions<T> IsTrue(Predicate<T> condition)
        {
            return this;
        }

        public PropertyArgumentExpression<T, TProp> Property<TProp>(Func<T, TProp> valueCallback, string name)
        {
            return new NullPropertyArgumentExpression<T, TProp>(this, default(TProp), name);
        }

        public IArgumentExpressions<T> Property<TProp>(Func<T, TProp> valueCallback, string name, Action<IArgumentExpressions<TProp>> assertions)
        {
            assertions.Invoke(NullArgumentExpressionsImpl<TProp>.Instance);
            return this;
        }
    }
}
